home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The X-Philes (2nd Revision)
/
The X-Philes Number 1 (1995).iso
/
xphiles
/
hp48_2
/
star-1_0.tar
/
expr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-03-22
|
12KB
|
657 lines
/* expr.c -- STAR Expression Evaluator
This file is part of STAR, the Saturn Macro Assembler.
STAR is not distributed by the Free Software Foundation. Do not ask
them for a copy or how to obtain new releases. Instead, send e-mail to
the address below. STAR is merely covered by the GNU General Public
License.
Please send your comments, ideas, and bug reports to
Jan Brittenson <bson@ai.mit.edu>
*/
/* Copyright (C) 1990, 1991 Jan Brittenson.
STAR is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
STAR is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with STAR; see the file COPYING. If not, to obtain a copy, write
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
USA, or send e-mail to bson@ai.mit.edu. */
#include <stdio.h>
#include <math.h>
#include "sects.h"
#include "star.h"
#include "symbols.h"
#include "ctt.h"
/* External functions/data */
extern SYM_ROOT
*symtbl;
extern
mtstr(), errcnt, pass;
/* Global functions/data */
CTT_ROOT
*reg_table, /* Register transition tree */
*opx_table, /* OPX transition tree */
*xopy_table; /* XOPY transition tree */
struct val
(*defrdx)(); /* Default radix parser */
struct fstruct
*fhit; /* Last operator called */
/* A few constants */
struct val
val_zero, /* INT 0 */
val_one, /* INT 1 */
val_real0, /* REAL 0 */
val_real1, /* REAL 1 */
val_nullstr; /* STRING `' */
/* Local data (externally accessible) */
char
expr_strings[32768], /* 32kB of expression data space */
*expr_allp; /* Allocation pointer */
/* Initialize constants, etc */
void expr_init()
{
expr_allp = expr_strings;
val_zero.type = VT_INT;
val_zero.vint = 0;
val_one.type = VT_INT;
val_one.vint = 1;
val_nullstr.type = VT_STR;
val_nullstr.vstr = "";
val_real0.type = val_real1.type = VT_REAL;
val_real0.vdouble = 0.0;
val_real1.vdouble = 1.0;
}
/* Wrap integer into value */
#ifndef __GNUC__
struct val intval(i)
INT i;
{
struct val tmp;
tmp.type = VT_INT;
tmp.vint = i;
return(tmp);
}
#endif
/* True if data is in expression space */
isexpr_data(p)
char *p;
{
return(p >= expr_strings &&
p <= expr_strings + sizeof expr_strings);
}
/* Allocate data in expression space */
char *expr_alloc(nbytes)
int nbytes;
{
register char *tmp = expr_allp;
if(nbytes & 15)
nbytes = (nbytes & ~15) + 16;
if((expr_allp += nbytes) >= expr_strings + sizeof expr_strings)
fatal("Can't allocate %d bytes: expression data space exhausted",
nbytes);
return(tmp);
}
/* Duplicate string in space reclaimable by expr_gc */
char *expr_strdup(str)
char *str;
{
register char *tmp;
int n = strlen(str)+1;
tmp = expr_alloc(n);
bcopy(str, tmp, n+1);
return(tmp);
}
/* Duplicate macro in space reclaimable by expr_gc */
struct macro *expr_dupmacro(mp)
struct macro *mp;
{
int msize = sizeof *mp + (mp->nlines - 1) * sizeof(char *);
char **l;
struct marg *ma;
struct macro *m;
/* Start out with current block data */
m = (struct macro *) expr_alloc(msize);
bcopy(mp, m, msize);
/* Duplicate lines */
for(l = m->lines; l < m->lines + m->nlines; l++)
*l = expr_strdup(*l);
/* Duplicate argument default values, if any*/
for(ma = m->args; ma < m->args + m->nargs; ma++)
ma->def = (ma->def ? expr_strdup(ma->def) : NULL);
return(m);
}
/* Duplicate macro */
struct macro *dupmacro(mp)
struct macro *mp;
{
int msize = sizeof *mp + (mp->nlines - 1) * sizeof(char *);
char **l;
struct marg *ma;
struct macro *m;
extern char *malloc(), *strdup();
/* Start out with current block data */
if(!(m = (struct macro *) malloc(msize)))
fatal("Can't allocate %d bytes for macro definition", msize);
bcopy(mp, m, msize);
/* Duplicate lines */
for(l = m->lines; l < m->lines + m->nlines; l++)
*l = strdup(*l);
/* Duplicate argument defaults */
for(ma = m->args; ma < m->args + m->nargs; ma++)
{
ma->def = (ma->def ? strdup(ma->def) : NULL);
}
return(m);
}
/* Reclaim expr alloc space */
void expr_gc()
{
expr_allp = expr_strings;
}
/* Make recoverable copy of value */
struct val localize(v)
struct val v;
{
switch(v.type)
{
case VT_INT:
case VT_REAL: return(v);
case VT_STR:
v.vstr = expr_strdup(v.vstr);
return(v);
case VT_MAC:
v.vmacro = expr_dupmacro(v.vmacro);
return(v);
case VT_SECT:
default:
return(v);
}
}
/* Duplicate string */
char *strdup(s)
char *s;
{
register char *tmp;
extern char *malloc();
if(!(tmp = malloc(strlen(s)+1)))
fatal("Can't allocate %d characters for string data", strlen(s)+1);
strcpy(tmp, s);
return(tmp);
}
/* Make value independent of expr recoverable areas */
struct val solidify(v)
struct val v;
{
switch(v.type)
{
case VT_INT:
case VT_REAL: return(v);
case VT_STR:
v.vstr = strdup(v.vstr);
return(v);
case VT_MAC:
v.vmacro = dupmacro(v.vmacro);
return(v);
case VT_SECT:
default:
return(v);
}
}
/* Convert to string, output is localized */
struct val tostr(v)
struct val v;
{
char bf[64];
switch(v.type)
{
case VT_STR: return(v);
case VT_REAL:
#ifdef __GNUC__
sprintf(bf, "%lg", (double) v.vdouble);
#else
sprintf(bf, "%g", (double) v.vdouble);
#endif
v.type = VT_STR;
v.vstr = expr_strdup(bf);
return(v);
case VT_INT:
sprintf(bf, "%ld", (INT) v.vint);
v.type = VT_STR;
v.vstr = expr_strdup(bf);
return(v);
case VT_SECT:
case VT_MAC:
default:
v.type = VT_STR;
v.vstr = expr_strdup("");
return(v);
}
}
/* Wrap double as real */
#ifndef __GNUC__
struct val realval(d)
REAL d;
{
struct val dval;
dval.type = VT_REAL;
dval.vdouble = d;
return(dval);
}
#endif
/* Convert to real */
struct val toreal(v)
struct val v;
{
switch(v.type)
{
case VT_REAL: return(v);
case VT_INT:
v.type = VT_REAL;
v.vdouble = (REAL) v.vint;
return(v);
case VT_STR:
return(toreal(toint(v)));
case VT_SECT:
return(toreal(intval(v.vsect->sc_reloc)));
case VT_MAC:
default:
return(val_real0);
}
}
/* Convert to integer */
struct val toint(v)
struct val v;
{
register unsigned char *cp;
register l;
register INT acc;
switch(v.type)
{
case VT_REAL:
v.type = VT_INT;
v.vint = (INT) v.vdouble;
/* Drop */
case VT_INT:
return(v);
case VT_STR:
v.type = VT_INT;
if((l = strlen(v.vstr)) > sizeof v.vint)
l = sizeof v.vint;
for(acc = 0, cp = (unsigned char *) v.vstr+l;
cp > (unsigned char *) v.vstr; acc += *--cp)
acc <<= 8;
v.vint = acc;
return(v);
case VT_SECT:
return(intval(v.vsect->sc_reloc));
default:
return(val_zero);
}
}
/* Test if end of expression
* Arguments are terminated if end of string, ';', ',' or '>'
* Spaces are bypassed.
*/
#ifndef eoe
static eoe(cp)
char *cp;
{
/* Does it match the termination condition? */
return(!cp ||
*cp < '\040' || *cp == ';' || *cp == '(' || *cp == ',' ||
*cp == ':' || *cp == '[' || *cp == ')' || *cp == ']');
}
#endif
/* Initialize parse transition tables */
void init_op_tables()
{
struct fstruct *opp;
SYM_NODE *opsym;
int isopx;
char opname[64];
struct val opval;
extern struct fstruct
funtbl[], regtbl[];
/* Initialize tables */
opx_table = ctt_new();
xopy_table = ctt_new();
reg_table = ctt_new();
/* Loop tables and add */
for(opp = funtbl; opp->name; opp++)
{
isopx = opp->type & OPX;
sprintf(opname, "%c%s", (isopx ? ';' : ','), opp->name);
opval.type = VT_OP;
opval.vop = opp;
opsym = sm_enter_sym(symtbl, opname, opval, F_HID);
ctt_add((isopx ? opx_table : xopy_table), opp->name, opsym);
}
for(opp = regtbl; opp->name; opp++)
{
sprintf(opname, ":%s", opp->name);
opval.type = VT_OP;
opval.vop = opp;
opsym = sm_enter_sym(symtbl, opname, opval, F_HID);
ctt_add(reg_table, opp->name, opsym);
}
}
/* Match OPX op */
mtopx(cpp, funp)
char **cpp;
struct fstruct **funp;
{
SYM_NODE *opsym;
if(!cpp)
return(FALSE);
#ifdef NEVER
printf("mtopx(`%s'): called\n", *cpp); /* DEBUG */
#endif
if((opsym = ctt_find(opx_table, cpp)) && (opsym->value.type == VT_OP))
{
#ifdef NEVER
printf("mtopx: OPX match, rest=`%s'\n", *cpp); /* DEBUG */
#endif
fhit = *funp = opsym->value.vop;
return(TRUE);
}
#ifdef NEVER
printf("mtopx: no match, rest=`%s'\n", *cpp); /* DEBUG */
#endif
return(FALSE);
}
/* Match XOPY op */
mtxopy(cpp, funp)
char **cpp;
struct fstruct **funp;
{
SYM_NODE *opsym;
if((opsym = ctt_find(xopy_table, cpp)) && (opsym->value.type == VT_OP))
{
fhit = *funp = opsym->value.vop;
return(TRUE);
}
return(FALSE);
}
/* Evaluate a simple term.
* Parse symbol names and default radix numbers.
*/
evsimple(cpp, lp)
char **cpp;
struct val *lp;
{
struct sstruct *symp;
char csav, *sp;
sp = *cpp;
/* Parse numeric if numerical
* Must be called before 'issym' because
* '0'-'9' are valid symbol characters.
*/
if(**cpp >= '0' && **cpp <= '9')
{
/* Call default radix parser */
*lp = (*defrdx)(cpp);
return(TRUE);
}
/* Is it a symol? */
if(!issym(*sp))
{
*lp = val_zero;
return(FALSE);
}
/* Assume symbol. Set sp to point at first invalid character */
for(sp = *cpp; issym(*sp); sp++);
/* Save old character and zero terminate */
csav = *sp;
*sp = '\0';
if(!(symp = sm_find_sym(symtbl, *cpp)) || (symp->flags & F_UDF))
{
*lp = localize(val_nullstr);
sgnerr("Undefined symbol `%s'", *cpp);
}
else
{
*lp = localize(symp->value);
symp->flags |= F_REF;
}
/* Skip past symbol and return copy of its value */
*cpp = sp;
*sp = csav;
*cpp = byspace(*cpp);
return(TRUE);
}
/* Evaluate term */
static struct val evterm(cpp)
char **cpp;
{
struct fstruct *funp;
struct val tmpacc;
*cpp = byspace(*cpp);
/* Look if we have an OPX op */
if(mtopx(cpp, &funp))
/* Fast evaluation? */
if(funp->type & F_FAST)
/* Yes */
return((*funp->feval)(cpp));
else
/* No, recurse until there is no more left */
return((*funp->feval)(cpp, evterm(cpp)));
/* No, go for simple term */
if(!evsimple(cpp, &tmpacc))
sgnerr("Bad expression syntax");
/* Return value of term */
return(tmpacc);
}
/* Evaluate an 'op term' pair */
static int evalop(cpp, accp)
char **cpp;
struct val *accp;
{
struct fstruct *funp;
struct val termacc;
/* Make sure we have an XOPY op */
if(!mtxopy(cpp, &funp))
{
sgnerr("Bad expression, operator expected");
return(FALSE);
}
/* Now evaluate term */
termacc = evterm(cpp);
/* Evaluate XOPY and update accumulator */
*accp = (*funp->feval)(cpp, *accp, termacc);
return(TRUE);
}
/* Evaluate an expression */
struct val evexpr(cpp)
char **cpp;
{
struct val acc;
/* Evaluate term */
acc = evterm(cpp);
/* Test if end of expression */
if(eoe(*cpp))
return(acc);
/* The following is: op term op term ... op term */
for(;;)
{
*cpp = byspace(*cpp);
/* End of expression? */
if(eoe(*cpp))
return(acc);
/* No - XOPY TERM follows */
if(!evalop(cpp, &acc))
return(acc);
}
}